package org.jetlinks.community.codec;

import lombok.NoArgsConstructor;
import org.apache.commons.lang.math.NumberUtils;
import org.hswebframework.ezorm.core.ValueCodec;

import java.sql.Timestamp;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;

@NoArgsConstructor
public class LocalDateTimeCodec implements ValueCodec {

    private Class toType;
    private String format;

    public LocalDateTimeCodec(String format, Class toType) {
        this.format = format;
        this.toType = toType;
    }

    protected LocalDateTime doParse(String dateString) {
        return LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern(format));
    }

    @Override
    public Object encode(Object value) {
        if (value instanceof LocalDateTime) {
            return value;
        }
        if (value instanceof Long) {
            return LocalDateTime.ofInstant(Instant.ofEpochSecond((Long) value), ZoneId.systemDefault());
        }
        if (value instanceof String) {
            if (NumberUtils.isNumber((String) value)) {
                return LocalDateTime.ofInstant(Instant.ofEpochMilli(Long.parseLong((String) value)), ZoneId.systemDefault());
            }

            return doParse(((String) value));
        }
        return value;
    }

    @Override
    @SuppressWarnings("all")
    public Object decode(Object data) {
        if (null == data) {
            return null;
        }
        if (toType.isAssignableFrom(data.getClass())) {
            return data;
        }
        if (data instanceof Number) {
            data = LocalDateTime.ofInstant(Instant.ofEpochSecond(((Number) data).longValue()), ZoneId.systemDefault());
        } else if (data instanceof Timestamp) {
            data = ((Timestamp) data).toLocalDateTime();
        } else if (data instanceof Instant) {
            data = ((Instant) data).atZone(ZoneId.systemDefault()).toLocalDateTime();
        } else if (data instanceof LocalDateTime) {
            data = ((LocalDateTime) data);
        } else if (data instanceof ZonedDateTime) {
            data = ((ZonedDateTime) data).toLocalDateTime();
        }
        if (data instanceof LocalDateTime) {
            if (toType == LocalDateTime.class) {
                return data;
            }
            if (toType == Instant.class) {
                return ((LocalDateTime) data).toInstant(ZoneOffset.UTC);
            }
            if (toType == LocalDate.class) {
                return ((LocalDateTime) data).toLocalDate();
            }
            if (toType == LocalTime.class) {
                return ((LocalDateTime) data).toLocalTime();
            }
            if (toType == Date.class) {
                return Date.from(((LocalDateTime) data).atZone(ZoneId.systemDefault()).toInstant());
            }
            if (toType == String.class) {
                return ((LocalDateTime) data).format(DateTimeFormatter.ofPattern(format));
            }
        }
        return data;
    }
}
